﻿#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Linq.Expressions;
using NUnit.Framework;
using Newtonsoft.Utilities.Reflection;

namespace Newtonsoft.Utilities.Tests.Reflection
{
	public class ReflectorTests : TestsBase
	{
    [Test]
    public void ShouldGetConstructor()
    {
      ConstructorInfo constructorInfo = Reflector.GetConstructor<Mock>(() => new Mock(default(Version), default(int)));
      Assert.IsTrue(constructorInfo == typeof(Mock).GetConstructor(new Type[] { typeof(Version), typeof(int) }));
    }

    [Test]
    public void ShouldGetAutomaticEvent()
    {
      EventInfo eventInfo = Reflector.GetEvent<ReflectorTests>(x => x.TestAutomaticEvent(null, null));
      Assert.IsTrue(eventInfo == typeof(ReflectorTests).GetEvent("TestAutomaticEvent"));
    }

    //[Test]
    //public void ShouldGetManualEvent()
    //{
    //  EventInfo eventInfo = Reflector.GetEvent<ReflectorFixture>(x => x.TestManualEvent(null, null));
    //  Assert.IsTrue(eventInfo == typeof(ReflectorFixture).GetEvent("TestManualEvent"));
    //}
    
    [ExpectedException(typeof(ArgumentNullException))]
		[Test]
		public void ShouldThrowIfNullMethodLambda()
		{
      Reflector.GetMethod<Mock>((Expression<Action<Mock>>)null);
		}

		[ExpectedException(typeof(ArgumentNullException))]
		[Test]
		public void ShouldThrowIfNullPropertyLambda()
		{
      Reflector.GetProperty<Mock>((Expression<Func<Mock, object>>)null);
		}

		[ExpectedException(typeof(ArgumentNullException))]
		[Test]
		public void ShouldThrowIfNullFieldLambda()
		{
      Reflector.GetField<Mock>((Expression<Func<Mock, object>>)null);
		}

		[ExpectedException(typeof(ArgumentException))]
		[Test]
		public void ShouldThrowIfNotMethodLambda()
		{
      Reflector.GetMethod<Mock>(x => new object());
		}

		[ExpectedException(typeof(ArgumentException))]
		[Test]
		public void ShouldThrowIfNotPropertyLambda()
		{
      Reflector.GetProperty<Mock>(x => x.PublicField);
		}

		[ExpectedException(typeof(ArgumentException))]
		[Test]
		public void ShouldThrowIfNotFieldLambda()
		{
      Reflector.GetField<Mock>(x => x.PublicProperty);
		}

		[Test]
		public void ShouldGetPublicProperty()
		{
      PropertyInfo info = Reflector.GetProperty<Mock>(x => x.PublicProperty);
      Assert.IsTrue(info == typeof(Mock).GetProperty("PublicProperty"));
		}

		[Test]
		public void ShouldGetPublicField()
		{
      FieldInfo info = Reflector.GetField<Mock>(x => x.PublicField);
      Assert.IsTrue(info == typeof(Mock).GetField("PublicField"));
		}

		[Test]
		public void ShouldGetPublicVoidMethod()
		{
      MethodInfo info = Reflector.GetMethod<Mock>(x => x.PublicVoidMethod());
      Assert.IsTrue(info == typeof(Mock).GetMethod("PublicVoidMethod"));
		}

		[Test]
		public void ShouldGetPublicMethodParameterless()
		{
      MethodInfo info = Reflector.GetMethod<Mock>(x => x.PublicMethodNoParameters());
      Assert.IsTrue(info == typeof(Mock).GetMethod("PublicMethodNoParameters"));
		}

		[Test]
		public void ShouldGetPublicMethodParameters()
		{
			MethodInfo info = Reflector.GetMethod<Mock>(x => x.PublicMethodParameters(default(string), default(int)));
			Assert.IsTrue(info == typeof(Mock).GetMethod("PublicMethodParameters", new Type[] { typeof(string), typeof(int) }));
		}

		[Test]
		public void ShouldGetNonPublicProperty()
		{
      PropertyInfo info = Reflector.GetProperty<ReflectorTests>(x => x.NonPublicProperty);
      Assert.IsTrue(info == typeof(ReflectorTests).GetProperty("NonPublicProperty", BindingFlags.Instance | BindingFlags.NonPublic));
		}

		[Test]
		public void ShouldGetNonPublicField()
		{
      FieldInfo info = Reflector.GetField<ReflectorTests>(x => x.NonPublicField);
      Assert.IsTrue(info == typeof(ReflectorTests).GetField("NonPublicField", BindingFlags.Instance | BindingFlags.NonPublic));
		}

		[Test]
		public void ShouldGetNonPublicMethod()
		{
      MethodInfo info = Reflector.GetMethod<ReflectorTests>(x => x.NonPublicMethod());
      Assert.IsTrue(info == typeof(ReflectorTests).GetMethod("NonPublicMethod", BindingFlags.Instance | BindingFlags.NonPublic));
		}

    public event ResolveEventHandler TestAutomaticEvent;
    public event ResolveEventHandler TestManualEvent
    {
      add { }
      remove { }
    }

    //public event ResolveEventHandler TestEvent;

		private int NonPublicField;

		private int NonPublicProperty
		{
			get { return NonPublicField; }
			set { NonPublicField = value; }
		}

		private object NonPublicMethod()
		{
			throw new NotImplementedException();
		}

		public class Mock
		{
      
      public int Value;
			public bool PublicField;
			private int valueProp;

			public Mock()
			{
			}

			public Mock(string foo, int bar)
			{
			}

      public Mock(Version v, int bar)
      {
      }

			public int PublicProperty
			{
				get { return valueProp; }
				set { valueProp = value; }
			}

			public bool PublicMethodNoParameters()
			{
				throw new NotImplementedException();
			}

			public bool PublicMethodParameters(string foo, int bar)
			{
				throw new NotImplementedException();
			}

			public void PublicVoidMethod()
			{
				throw new NotImplementedException();
			}
		}
	}
}
